package top.huhuiyu.springboot3.p2301.service.impl;

import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import top.huhuiyu.springboot3.p2301.base.R;
import top.huhuiyu.springboot3.p2301.entity.TbFile;
import top.huhuiyu.springboot3.p2301.exception.AppException;
import top.huhuiyu.springboot3.p2301.mapper.TbFileMapper;
import top.huhuiyu.springboot3.p2301.service.FileService;

import java.io.*;

@Service
@RequiredArgsConstructor
@Slf4j
// 如果捕获到异常就会回顾事务，取消所有的数据库修改动作
@Transactional(rollbackFor = Exception.class)
public class FileServiceImpl implements FileService {
    private final TbFileMapper tbFileMapper;

    @Override
    public R<TbFile> upload(String fileinfo, MultipartFile file) {
        if (file == null) {
            return R.fail("没有上传文件信息", null);
        }
        // 第一步是保存信息到数据库
        TbFile tbFile = new TbFile();
        tbFile.setFileName(file.getOriginalFilename());
        tbFile.setFileInfo(fileinfo);
        tbFile.setContentType(file.getContentType());
        tbFile.setFileSize(file.getSize());
        int i = tbFileMapper.insert(tbFile);
        if (i != 1) {
            return R.fail("保存文件信息失败", null);
        }
        // 第二步是保存文件
        try {
            File saveFile = new File(UPLOAD_DIR, String.format(FILE_SAVE_NAME, tbFile.getId(), tbFile.getFileName()));
            InputStream is = file.getInputStream();
            OutputStream os = new FileOutputStream(saveFile);
            byte[] buffer = new byte[8 * 1024];
            int len = is.read(buffer);
            while (len > 0) {
                os.write(buffer, 0, len);
                os.flush();
                len = is.read(buffer);
            }
            os.close();
            is.close();
        } catch (Exception ex) {
            // 数据库保存信息之后的任何操作失败，都需要抛出异常来回滚事务
            log.error("保存文件失败", ex);
            throw AppException.create("保存文件失败");
        }
        return R.ok(tbFile);
    }


    @Override
    public void download(Integer id, HttpServletResponse response) {
        // 查询数据文件是否存在
        TbFile tbFile = tbFileMapper.selectById(id);
        if (tbFile == null) {
            downloadError("文件信息不存在", response);
            return;
        }
        // 校验本地文件是否存在
        File file = new File(UPLOAD_DIR, String.format(FILE_SAVE_NAME, tbFile.getId(), tbFile.getFileName()));
        if (!file.exists()) {
            downloadError("文件不存在", response);
            return;
        }
        // 自定义文件应答
        response.reset();
        response.setContentType(tbFile.getContentType());
        try {
            String fileName = new String(tbFile.getFileName().getBytes(), "ISO-8859-1");
            // 告诉浏览器实际的文件名称
            response.setHeader("Content-Disposition", String.format("attachment;filename=%s", fileName));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        try {
            InputStream is = new FileInputStream(file);
            OutputStream os = response.getOutputStream();
            byte[] buffer = new byte[8 * 1024];
            int len = is.read(buffer);
            while (len > 0) {
                os.write(buffer, 0, len);
                os.flush();
                len = is.read(buffer);
            }
            os.close();
            is.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void downloadError(String message, HttpServletResponse response) {
        // 无法正常应答的结果处理
        response.reset();
        response.setContentType("text/plain");
        response.setCharacterEncoding("UTF-8");
        try {
            PrintWriter writer = response.getWriter();
            writer.write(message);
            writer.flush();
            writer.close();
        } catch (Exception e) {
            throw AppException.create(e.getMessage());
        }
    }


    @Override
    public void url(Integer id, HttpServletResponse response) {
        // 获取文件信息
        TbFile tbFile = tbFileMapper.selectById(id);
        String filename = tbFile == null ? "" : tbFile.getFileName();
        filename = String.format(FILE_SAVE_NAME, id, filename);
        // 重定向到静态服务器上的文件
        try {
            response.sendRedirect(FILE_URL + filename);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
